/*
 *    Copyright (C) 2011-2012 Hai Bison
 *
 *    See the file LICENSE at the root directory of this project for copying
 *    permission.
 */

package group.pals.mailgate.ui;

import group.pals.threads.BaseThread;
import group.pals.threads.listeners.ThreadListener;
import java.awt.Point;
import java.awt.Window;
import java.awt.event.WindowAdapter;
import java.awt.event.WindowEvent;
import java.util.Random;

/**
 *
 * @author Hai Bison
 */
public class WindowTransformer extends BaseThread {

    public static final boolean Debug = false;
    private final Window _Window;
    private final Point FromLocation;
    private final Point ToLocation;
    private final int DelayTime;

    /**
     * Creates new {@link WindowTransformer} to move {@link Window} from {@code fromLocation}
     * to {@code toLocation}, in {@code delayTime} (milliseconds).
     * @param window
     * @param fromLocation
     * @param toLocation
     * @param delayTime 
     */
    public WindowTransformer(Window window, Point fromLocation, Point toLocation,
            int delayTime) {
        super(null);

        this._Window = window;
        this.FromLocation = fromLocation;
        this.ToLocation = toLocation;
        this.DelayTime = delayTime > 0 ? delayTime : 1;
    }

    @Override
    public void run() {
        debugOutput("from = %s", FromLocation);
        debugOutput("to = %s", ToLocation);

        /*
         * calculate time step and step-xy;
         * if time > distance:
         * - time step = time / distance
         * - step-xy = 1
         * else if time <= distance:
         * - time step = 1
         * - step-xy = distance / time
         */
        double distance = Math.abs(FromLocation.x - ToLocation.x) + Math.abs(FromLocation.y - ToLocation.y);
        debugOutput("distance = %f", distance);

        double stepxy = 1;
        int delayTimePerStep = 1;
        if (DelayTime > distance) {
            delayTimePerStep = (int) (DelayTime / distance);
        } else {
            stepxy = distance / DelayTime;
        }

        debugOutput("delayTimePerStep = %d", delayTimePerStep);
        debugOutput("stepxy = %f", stepxy);

        /*
         * A----------->----------a    a-----------<----------A
         * |    .                 |    |                 .    |
         * |           .          |    |           .          |
         * |                  .   |    |    .                 |
         * b----------->----------B    B-----------<----------b
         * - sinx = sin(ABa)           - sinx = sin(ABa)
         * - siny = sin(ABb)           - siny = sin(ABb)
         * 
         * B-----------<----------b    b----------->----------B
         * |    .                 |    |                 .    |
         * |           .          |    |           .          |
         * |                  .   |    |    .                 |
         * a-----------<----------A    A----------->----------a
         * - sinx = sin(ABa)           - sinx = sin(ABa)
         * - siny = sin(ABb)           - siny = sin(ABb)
         */

        /*
         * calculate factors
         */
        int factorx = ToLocation.x > FromLocation.x ? 1 : -1;
        int factory = ToLocation.y > FromLocation.y ? 1 : -1;

        //prepare listener
        WindowAdapter winListener = new WindowAdapter() {

            @Override
            public void windowClosing(WindowEvent e) {
                interrupt();
            }

            @Override
            public void windowIconified(WindowEvent e) {
                interrupt();
            }
        };
        _Window.addWindowListener(winListener);

        /*
         * now transform the window  :-), oh my bad math hurts my head!
         */
        final boolean IsXFirst = new Random().nextInt() % 2 == 0;
        final long TimeStarting = System.currentTimeMillis();
        int passedStep = 0;
        while (!isInterrupted() && System.currentTimeMillis() - TimeStarting < DelayTime) {
            if (IsXFirst) {
                if (passedStep < Math.abs(FromLocation.x - ToLocation.x)) {
                    FromLocation.x += stepxy * factorx;
                } else {
                    FromLocation.y += stepxy * factory;
                }
            } else {
                if (passedStep < Math.abs(FromLocation.y - ToLocation.y)) {
                    FromLocation.y += stepxy * factory;
                } else {
                    FromLocation.x += stepxy * factorx;
                }
            }
            passedStep++;
            _Window.setLocation(FromLocation);
            try {
                sleep(delayTimePerStep);
            } catch (InterruptedException ie) {
                debugOutput("...interrupted");
                interrupt();
            }
        }

        //make sure if our code is wrong...  :-D
        _Window.setLocation(ToLocation);
        _Window.removeWindowListener(winListener);

        for (ThreadListener listener : Listeners) {
            listener.threadTerminated(this);
        }
    }

    private void debugOutput(Object msg) {
        if (Debug) {
            System.out.println(String.format("[DEBUG] %s [%s] :: %s",
                    WindowTransformer.class.getName(), new java.util.Date(), msg));
        }
    }

    private void debugOutput(Object msg, Object... args) {
        debugOutput(String.format(msg.toString(), args));
    }
}
